<script setup lang="ts">
import type { ArticleCover } from '@/types/article'
import type { ImageData, PublishReqParams } from '@/types/publish.d.ts'
import { computed, ref, onMounted, shallowRef, onBeforeUnmount } from 'vue'
import { useUserStore } from '@/stores/user'
import { baseURL } from '@/utils/http'
import { ElMessage, type UploadFile } from 'element-plus'
import type { ResponseData } from '@/types'
import { getArticleDetailApi, publishArticleApi, updateArticleApi } from '@/apis/publish'
import { useRouter } from 'vue-router'
import { useRoute } from 'vue-router'
// 王富文本
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import type { IEditorConfig } from '@wangeditor/editor'
import type { IDomEditor } from '@wangeditor/editor'

const route = useRoute()

// 获取路由信息
const getChannelId = async () => {
  console.log(route.query.id)
  if (route.query.id) {
    await getArticleDetail(route.query.id.toString())
  }
}

onMounted(() => {
  getChannelId()
})

// 获取文章详情
const getArticleDetail = async (id: string) => {
  const res = await getArticleDetailApi(id)
  formModel.value = {
    title: res.title,
    channel_id: res.channel_id,
    cover: res.cover,
    content: res.content,
  }
}
const router = useRouter()
const { token } = useUserStore()

const formModel = ref<PublishReqParams>({
  title: undefined,
  channel_id: undefined,
  cover: {
    type: 1,
    images: [],
  },
  content: undefined,
})
const rules = {
  title: [
    { required: true, message: '请输入文章标题', trigger: 'blur' },
    { min: 4, max: 50, message: '文章标题4-50字符', trigger: 'blur' },
  ],
  channel_id: [{ required: true, message: '请选择文章频道', trigger: 'change' }],
  cover: [
    { required: true, message: '请上传图片', trigger: 'change' },
    // 自定义校验
    {
      validator: (rule: unknown, value: ArticleCover, cb: (err?: Error) => void) => {
        // value === this.articleForm.cover 封面对象
        // 1. 单图 type === 1  校验 images 中有一张图片
        // 2. 单图 type === 3  校验 images 中有三张图片
        // 其他情况正确
        if (value.type === 1) {
          if (!value.images[0]) {
            cb(new Error('请上传一张图片'))
          }
        }

        if (value.type === 3) {
          if (!(value.images[0] && value.images[1] && value.images[2])) {
            cb(new Error('请上传三张图片'))
          }
        }

        cb()
      },
      trigger: 'change',
    },
  ],
  content: [
    { required: true, message: '请输入文章内容', trigger: 'blur' },
    {
      validator: (rule: unknown, value: string, callback: (err?: Error) => void) => {
        if (value == '<p><br></p>') {
          callback(new Error('请输入文章内容'))
        } else {
          callback()
        }
      },
      trigger: 'blur',
    },
  ],
}
const formRef = ref()
const upload = ref()
const fileList = computed(() => {
  return formModel.value.cover.images.map((item) => ({ url: item }))
})
// 切换封面类型
const changeCoverType = () => {
  // 重置数据
  formModel.value.cover.images = []
  // 重置组件
  upload.value.clearFiles()
  // 自己再次校验
  formRef.value.validateField('cover')
}
// 上传图片成功
const uploadSuccess = (res: ResponseData<ImageData>) => {
  // res就是响应数据
  formModel.value.cover.images.push(res.data.url)
  // 触发一次校验
  formRef.value.validateField('cover')
}
// 删除文件
const removeFile = (file: UploadFile) => {
  // 主动：删除images数组中对应的图片
  // 1.发布的时候 file 中保存了之前上传图片响应的信息 response.data.url 图片地址
  // 2.编辑的时候 file-list 属性，导致file就是{url:'xxxxxxx'}
  // 根据这个图片地址找到images对应的索引，通过splice(索引,1) 删除图片
  const index = formModel.value.cover.images.findIndex((item) => item === file.url)
  formModel.value.cover.images.splice(index, 1)
  // 自己再次校验
  formRef.value.validateField('cover')
}
// 修改文章
const update = async (draft: boolean) => {
  await formRef.value.validate()

  try {
    // 2. 发请求
    await updateArticleApi(route.query.id!.toString(), draft, formModel.value)
    // get 获取  post 新增  delete 删除  put(完整修改) patch(局部修改) 修改
    // 满足以上规范的后台接口：resetfull 接口规范
    // 3. 成功
    ElMessage.success(draft ? '存入草稿成功' : '修改文章成功')
    router.replace('/article')
  } catch (e: unknown) {
    // 4. 失败
    console.log(e)
    ElMessage.error(draft ? '存入失败~' : '修改失败~')
  }
}
// 提交文章
const submit = async (draft: boolean) => {
  // 1. 校验
  await formRef.value.validate()

  try {
    // 2. 发请求
    await publishArticleApi(draft, formModel.value)
    // 3. 成功
    ElMessage.success(draft ? '存入草稿成功' : '发布文章成功')
    router.replace('/article')
  } catch (e: unknown) {
    // 4. 失败
    console.log(e)
    ElMessage.error(draft ? '存入失败~' : '发布失败~')
  }
}
/**
 * 富文本
 */
// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef()
const toolbarConfig = {}
const editorConfig: Partial<IEditorConfig> = { placeholder: '请输入内容...' }
const handleCreated = (editor: IDomEditor) => {
  editorRef.value = editor // 记录 editor 实例，重要！
}
// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return
  editor.destroy()
})
</script>

<template>
  <div class="publish-page">
    <el-card>
      <template v-slot:header>
        <div>
          <el-breadcrumb separator-class="el-icon-arrow-right">
            <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
            <el-breadcrumb-item>{{ $route.query.id ? '修改' : '发布' }}文章</el-breadcrumb-item>
          </el-breadcrumb>
        </div>
      </template>

      <!-- 表单 -->
      <el-form ref="formRef" :model="formModel" :rules="rules" label-width="120px">
        <el-form-item label="标题：" prop="title">
          <el-input
            style="width: 400px"
            v-model="formModel.title"
            placeholder="请输入文章标题"
          ></el-input>
        </el-form-item>
        <el-form-item label="频道：" prop="channel_id">
          <my-channel v-model="formModel.channel_id"></my-channel>
        </el-form-item>
        <el-form-item label="封面：" prop="cover">
          <el-radio-group @change="changeCoverType" v-model="formModel.cover.type">
            <el-radio :label="1">单图</el-radio>
            <el-radio :label="3">三图</el-radio>
            <el-radio :label="0">无图</el-radio>
            <el-radio :label="-1">自动</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item>
          <!-- 当封面类型：1，3 的时候使用组件 -->
          <!-- action 上传图片接口地址 -->
          <!-- list-type 上传后文件的显示形态，卡片 -->
          <!-- name="image" 文件数据的字段名称 -->
          <!-- header 配置请求头，类型对象 -->
          <el-upload
            v-if="formModel.cover.type === 1 || formModel.cover.type === 3"
            ref="upload"
            :action="baseURL + 'v1_0/upload'"
            name="image"
            :headers="{ Authorization: `Bearer ${token}` }"
            :limit="formModel.cover.type"
            :on-success="uploadSuccess"
            :on-remove="removeFile"
            :file-list="fileList"
            list-type="picture-card"
          >
            <el-icon class="avatar-uploader-icon"><Plus /></el-icon>
          </el-upload>
          <div v-else style="width: 178px; height: 178px"></div>
        </el-form-item>
        <el-form-item label="内容：" prop="content">
          <Toolbar
            style="border: 1px solid #ccc"
            :editor="editorRef"
            :defaultConfig="toolbarConfig"
            mode="default"
          />
          <Editor
            style="height: 300px; width: 100%; border: 1px solid #ccc"
            v-model="formModel.content"
            :defaultConfig="editorConfig"
            mode="default"
            @onCreated="handleCreated"
          />
        </el-form-item>
        <el-form-item label="" v-if="$route.query.id">
          <el-button @click="update(false)" type="success">修改文章</el-button>
          <el-button @click="update(true)">存入草稿</el-button>
        </el-form-item>
        <el-form-item label="" v-else>
          <div style="margin-top: 20px">
            <el-button @click="submit(false)" type="primary">发布文章</el-button>
            <el-button @click="submit(true)">存入草稿</el-button>
          </div>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<style scoped lang="less">
.el-select {
  width: 400px;
}
// scoped 当前写的样式是无法作用到其他组件内部标签（组件根元素可以作用）
::v-deep .el-upload-list__item {
  transition: none;
}
::v-deep .ql-editor {
  height: 200px;
}
.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
</style>
